package com.dudu.aspect;

import com.alibaba.fastjson.JSONObject;
import com.dudu.annotation.SystemServiceLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;


/**
 * Created by dudu on 16/8/5.
 */
@Slf4j
@Aspect
@Component
public  class LogAspect {

    //本地异常日志记录对象
//    private  static  final Logger logger = LoggerFactory.getLogger(LogAspect.class);

    //Service层切点
    @Pointcut("@annotation(com.dudu.annotation.SystemServiceLog)")
    public  void serviceAspect() {
    }

    @Pointcut("@annotation(com.dudu.annotation.SystemServiceLog)")
    private void ServiceMonitor() {
    }




    /**
     * 异常通知 用于拦截service层记录异常日志
     *
     * @param joinPoint
     * @param e
     */
    @AfterThrowing(pointcut = "serviceAspect()", throwing = "e")
    public  void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
        StringBuilder params = new StringBuilder();
        if (joinPoint.getArgs() !=  null && joinPoint.getArgs().length > 0) {
            for ( int i = 0; i < joinPoint.getArgs().length; i++) {
                params.append(joinPoint.getArgs()[i].toString()).append(";");
            }
        }
        try {
            log.error("=====异常通知开始=====");
            log.error("异常代码:" + e.getClass().getName());
            log.error("异常信息:" + e.getMessage());
            log.error("异常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
            log.error("方法描述:" + getServiceMthodDescription(joinPoint));
            log.error("请求参数:" + params.substring(0, params.length() - 2));
            log.error("=====异常通知结束=====");
        }  catch (Exception ex) {
            log.error("==异常通知异常==");
            log.error("异常信息:{}", ex.getMessage());
        }

    }
    

    @Around("ServiceMonitor()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        long begin = System.nanoTime();
        Object o = pjp.proceed();
        long end = System.nanoTime();
        log.info("方法名：" + getServiceMthodDescription(pjp));
        log.info("参数:" + JSONObject.toJSON(pjp.getArgs()));
        log.info("执行时间：" + (end - begin)/1000000 + " ms");
        return o;
    }


    /**
     * 获取注解中对方法的描述信息 用于service层注解
     *
     * @param joinPoint 切点
     * @return 方法描述
     * @throws Exception
     */
    public  static String getServiceMthodDescription(JoinPoint joinPoint)
            throws Exception {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        String description = "";
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
                    description = method.getAnnotation(SystemServiceLog.class).description();
                    break;
                }
            }
        }
        return description;
    }


}